package com.net.xpay.core.service.impl;

import com.alipay.api.AlipayApiException;
import com.alipay.api.response.AlipayFundBatchCreateResponse;
import com.alipay.api.response.AlipayFundBatchDetailQueryResponse;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.net.xpay.common.domain.User;
import com.net.xpay.common.domain.UserShard;
import com.net.xpay.common.manager.UserManager;
import com.net.xpay.common.manager.UserShardManager;
import com.net.xpay.common.model.TupleModel;
import com.net.xpay.core.constant.PoseidonErrorCode;
import com.net.common.exception.BusinessException;
import com.net.common.util.AlipayAccountCheckUtil;
import com.net.common.util.StreamUtil;
import com.net.xpay.alipay.PoseidonAlipayClient;
import com.net.xpay.alipay.enums.IdentityType;
import com.net.xpay.alipay.model.TransOrderModel;
import com.net.xpay.alipay.safePay.PoseidonSafePayAlipayClient;
import com.net.xpay.alipay.safePay.SafePayAlipayProperties;
import com.net.xpay.core.domain.AlipayUser;
import com.net.xpay.core.domain.PayTrans;
import com.net.xpay.core.enums.AlipayUserStatus;
import com.net.xpay.core.enums.PayTransStatus;
import com.net.xpay.core.helper.SignerCheckHelper;
import com.net.xpay.core.manager.AlipayUserManager;
import com.net.xpay.core.model.AlipayAuthModel;
import com.net.xpay.core.model.AlipayBatchAuthModel;
import com.net.xpay.core.service.OpenAlipayLogonIdAuthService;
import com.net.shard.ShardContextHolder;
import com.net.shard.ShardUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;

/**
 * 2020/6/28 10:58

 * 不要加事务这个类上
 */
@Slf4j
@Service
public class OpenAlipayLogonIdServiceImpl implements OpenAlipayLogonIdAuthService {

    private static final long PAY_BATCH_MAX_COUNT = 1000L;

    @Autowired
    private SignerCheckHelper signerCheckHelper;

    @Autowired
    private PoseidonAlipayClient xpayAlipayClient;

    @Autowired
    private AlipayUserManager alipayUserManager;

    @Autowired
    private UserShardManager userShardManager;

    @Autowired
    private UserManager userManager;

    @Autowired
    private PoseidonSafePayAlipayClient xpaySafePayAlipayClient;

    @Autowired
    private SafePayAlipayProperties safePayAlipayProperties;

    @Override
    public List<PayTrans> authAlipayLogonId(AlipayBatchAuthModel payModel) {
        //验证签名
        User user = signerCheckHelper.checkSign(payModel.getAppkey(), payModel.getTimestamp(), payModel.getSignature());
        payModel.setImportBatchNo(user.getId() + "_" + System.currentTimeMillis() + ThreadLocalRandom.current().nextInt(10000));
        TupleModel<List<PayTrans>, List<PayTrans>> tupleModel = checkPayModel(payModel, user);
        List<PayTrans> payTrans = tupleModel.getK();
        if (CollectionUtils.isEmpty(payTrans)) {
            return tupleModel.getV();
        }

        tupleModel.getK().addAll(tupleModel.getV());
        return tupleModel.getK();

//        //选择测试打款用的支付宝账号
//        AlipayUser alipayUser = chooseAlipayUser(payModel, user);
//        //创建支付宝批量打款订单
//        alipayFundBatchCreate(payModel, payTrans, alipayUser);
//
//        //查询结果
//        try {
//            Map<String/*outBizNo*/, PayTrans> payTransMap = StreamUtil.toMap(payTrans, PayTrans::getOutBizNo);
//            List<PayTrans> list = Lists.newArrayList();
//
//            ThreadUtil.safeSleep(1000L, "");
//            AlipayFundBatchDetailQueryResponse response = allDetailQuery(alipayUser, payModel.getImportBatchNo());
//            long queryCount = 0L;
//            while (queryCount < 10L) {
//                if (CollectionUtils.isEmpty(response.getAccDetailList())) {
//                    ThreadUtil.safeSleep(1000L, "");
//                    response = allDetailQuery(alipayUser, payModel.getImportBatchNo());
//                    queryCount++;
//                } else {
//                    break;
//                }
//            }
//
//            for (AccDetailModel accDetail : response.getAccDetailList()) {
//                PayTrans payTran = payTransMap.get(accDetail.getOutBizNo());
//                PayTransStatus status = PayTransStatus.of(accDetail.getStatus());
//                payTran.setDetailId(accDetail.getDetailId());
//                payTran.setErrorCode(accDetail.getErrorCode());
//                payTran.setErrorMsg(accDetail.getErrorMsg());
//                payTran.setStatus(status);
//                list.add(payTran);
//            }
//
//            tupleModel.getV().addAll(list);
//
//            return tupleModel.getV();
//
//        } catch (AlipayApiException e) {
//            log.error("authAlipayLogonId error|id={}", payModel.getImportBatchNo(), e);
//            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "检测失败");
//        }

    }

    private AlipayUser chooseAlipayUser(AlipayBatchAuthModel payModel, User user) {
        //先选择系统自带的账号
        AlipayUser alipayUser = null;
        try {
            alipayUser = chooseSystemAlipayUser();
        } catch (Exception e) {
            log.error("chooseAlipayUser sys error", e);
        }

        if (alipayUser != null) {
            return alipayUser;
        }
        if (!Strings.isNullOrEmpty(payModel.getAlipayNickName())) {
            alipayUser = alipayUserManager.findByAlipayNickName(user.getId(), payModel.getAlipayNickName());
            if (alipayUser == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "付款方支付宝账号不存在");
            }
        } else {
            if (user.getAlipayUserId() == null) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "请先绑定支付宝账号");
            }
            alipayUser = alipayUserManager.getById(user.getAlipayUserId());
        }

        if (alipayUser == null || alipayUser.getStatus() != AlipayUserStatus.YES) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "你的支付宝账号尚未签约，请先签约后再打款");
        }

//        if (alipayUser.getExpiresIn().isBefore(LocalDateTime.now())) {
//            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "支付宝账号签约已过期，请重新签约");
//        }

        return alipayUser;
    }

    private AlipayUser chooseSystemAlipayUser() {
        Long oldShardId = ShardContextHolder.getShardContext().getShardId();
        String systemAccount = "3405249757@qq.com";
        String systemMobile = "13524430274";

        User sysUser = userManager.findByMobile(systemMobile);
        UserShard userShard = userShardManager.getById(sysUser.getId());
        try {
            ShardUtil.setShardContext(userShard.getShardId());

            AlipayUser alipayUser = alipayUserManager.findByAlipayNickName(sysUser.getId(), systemAccount);
            if (alipayUser == null || alipayUser.getStatus() != AlipayUserStatus.YES) {
                return null;
            }

//            if (alipayUser.getExpiresIn().isBefore(LocalDateTime.now())) {
//                return null;
//            }
            log.info("chooseSystemAlipayUser user sys account={}", alipayUser.getAlipayNickName());
            return alipayUser;
        } finally {
            ShardUtil.setShardContext(oldShardId);
        }
    }

    @Override
    public List<PayTrans> authAlipayAccount(AlipayBatchAuthModel authModel) {
        return authAlipayLogonId(authModel);
        //没有安全付接口用老方法
//        if (!safePayAlipayProperties.getEnable()) {
//            return authAlipayLogonId(authModel);
//        }
//
//        //验证签名
//        User user = signerCheckHelper.checkSign(authModel.getAppkey(), authModel.getTimestamp(), authModel.getSignature());
//        authModel.setImportBatchNo(user.getId() + "_" + System.currentTimeMillis() + ThreadLocalRandom.current().nextInt(10000));
//        TupleModel<List<PayTrans>, List<PayTrans>> tupleModel = checkPayModel(authModel, user);
//
//        List<PayTrans> validAccounts = tupleModel.getK();
//        if (CollectionUtils.isEmpty(validAccounts)) {
//            return tupleModel.getV();
//        }
//
//
//        Map<String/*name|account*/, PayTrans> map = new HashMap<>();
//        for (PayTrans account : validAccounts) {
//            map.put(account.getName() + "|" + account.getIdentity(), account);
//            TransferUniFundModel model = TransferUniFundModel.getInstance();
//            model.setOrderTitle("代发");
//            model.setRemark("代发");
//            model.setTransAmount("0.1");
//            TransferUniFundModel.PayeeInfo payeeInfo = new TransferUniFundModel.PayeeInfo();
//            payeeInfo.setName(account.getName());
//            payeeInfo.setIdentity(account.getIdentity());
//            payeeInfo.setIdentityType(account.getIdentityType());
//            model.setPayeeInfo(payeeInfo);
//            model.setOutBizNo(account.getOutBizNo());
//            try {
//                AlipayFundTransUniTransferResponse resp = xpaySafePayAlipayClient.transferUniFund(model);
//                if (resp.isSuccess()) {
//                    //不能真的转账出去
//                    throw new BusinessException(PoseidonErrorCode.UNKNOWN_ERROR, "系统异常");
//                }
//                if (!"BALANCE_IS_NOT_ENOUGH".equals(resp.getSubCode())) {
//                    account.setErrorCode(resp.getSubCode());
//                    account.setErrorMsg(resp.getSubMsg());
//                }
//                //修改文案更易懂
//                if ("收款方账户收款额度已达上限，请收款方联系客服咨询详情。".equals(account.getErrorMsg())) {
//                    account.setErrorMsg("收款账户存在安全风险，被限制收款");
//                }
//            } catch (AlipayApiException e) {
////                account.setErrorMsg("未知异常");
////                account.setErrorCode("UNKNOWN_ERROR");
//                //新接口有异常，直接走老接口
//                return authAlipayLogonId(authModel);
//            }
//        }
//
//        //再用老接口查一遍
//        List<PayTrans> rets = authAlipayLogonId(authModel);
//        for (PayTrans payTrans : rets) {
//            if (!Strings.isNullOrEmpty(payTrans.getErrorMsg())) {
//                continue;
//            }
//            PayTrans selected = map.get(payTrans.getName() + "|" + payTrans.getIdentity());
//            if (selected != null && !Strings.isNullOrEmpty(selected.getErrorMsg())) {
//                payTrans.setErrorCode(selected.getErrorCode());
//                payTrans.setErrorMsg(selected.getErrorMsg());
//            }
//        }
//
//        return rets;
    }

    private AlipayFundBatchDetailQueryResponse allDetailQuery(AlipayUser alipayUser, String outBatchNo) throws AlipayApiException {
        AlipayFundBatchDetailQueryResponse toReturnResponse = detailQuery(alipayUser, outBatchNo, 1L);
        Long totalPageCount = toReturnResponse.getTotalPageCount();
        Long pageNum = 1L;
        while (pageNum <= totalPageCount) {
            pageNum++;
            if (pageNum <= totalPageCount) {
                AlipayFundBatchDetailQueryResponse response = detailQuery(alipayUser, outBatchNo, pageNum);
                toReturnResponse.getAccDetailList().addAll(response.getAccDetailList());
            }
        }
        return toReturnResponse;
    }

    private AlipayFundBatchDetailQueryResponse detailQuery(AlipayUser alipayUser, String outBatchId, long pageNum) throws AlipayApiException {
        return xpayAlipayClient.alipayFundBatchDetailQuery(alipayUser.getAuthToken(), outBatchId, pageNum);
    }

    private void alipayFundBatchCreate(AlipayBatchAuthModel payTransModel, List<PayTrans> payTrans, AlipayUser alipayUser) {
        TransOrderModel transOrderModel = buildTransOrderModel(payTransModel, payTrans);
        AlipayFundBatchCreateResponse response;
        try {
            response = xpayAlipayClient.alipayFundBatchCreate(alipayUser.getAuthToken(), transOrderModel);
        } catch (AlipayApiException e) {
            log.warn("alipayFundBatchCreate error|id={}", payTransModel.getImportBatchNo(), e);
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "检测失败" );
        }

        if (!response.isSuccess()) {
            log.warn("alipayFundBatchCreate failed importBatchNo={}|id={}|errorMsg={}", payTransModel.getImportBatchNo(),  response.getSubMsg() + "|" + response.getMsg());
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "检测失败");
        }
    }

    private TransOrderModel buildTransOrderModel(AlipayBatchAuthModel payTransModel, List<PayTrans> payTrans) {
        Function<PayTrans, BigDecimal> sum = ins -> new BigDecimal(ins.getTransAmount());

        TransOrderModel transOrderModel = TransOrderModel.getInstance();
        transOrderModel.setOutBatchNo(payTransModel.getImportBatchNo());
        transOrderModel.setTotalTransAmount(StreamUtil.sum(payTrans, sum).toString());
        transOrderModel.setTotalCount(String.valueOf(payTrans.size()));
        transOrderModel.setProductCode("BATCH_API_TO_ACC");
        transOrderModel.setBizScene("MESSAGE_BATCH_PAY");
        transOrderModel.setOrderTitle("转账");
        transOrderModel.setTimeExpire(null);
        transOrderModel.setRemark(null);
        List<TransOrderModel.TransOrderDetail> transOrderDetails = Lists.newArrayList();
        for (PayTrans record : payTrans) {
            TransOrderModel.TransOrderDetail detail = TransOrderModel.TransOrderDetail.getInstance();
            detail.setOutBizNo(record.getImportBizNo());
            detail.setTransAmount(record.getTransAmount());
            detail.setRemark(record.getRemark());

            TransOrderModel.PayeeInfo payeeInfo = TransOrderModel.PayeeInfo.getInstance();
            payeeInfo.setIdentity(record.getIdentity());
            payeeInfo.setIdentityType(record.getIdentityType());
            payeeInfo.setName(record.getName());

            detail.setPayeeInfo(payeeInfo);

            transOrderDetails.add(detail);
        }
        transOrderModel.setTransOrderList(transOrderDetails);
        return transOrderModel;
    }

    private TupleModel<List<PayTrans>, List<PayTrans>> checkPayModel(AlipayBatchAuthModel payModel, User merchant) {
        List<AlipayAuthModel> payTransModelList = payModel.getAccounts();
        if (CollectionUtils.isEmpty(payTransModelList)) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "至少检测一个账号");
        }
        if (payTransModelList.size() > PAY_BATCH_MAX_COUNT) {
            throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "一次检测不能超过" + PAY_BATCH_MAX_COUNT + "个");
        }

        List<PayTrans> payTrans = Lists.newArrayList();
        List<PayTrans> errors = Lists.newArrayList();

        for (int i = 0; i < payTransModelList.size(); i++) {
            AlipayAuthModel row = payTransModelList.get(i);
            String alipayNo = row.getIdentity();
            String name = row.getName();
            String identityType = row.getIdentityType();

            PayTrans instance = PayTrans.getInstance();
            instance.setImportBatchNo(payModel.getImportBatchNo());
            instance.setOutBizNo(merchant.getId() + "_" + System.currentTimeMillis() + "_" + i);
            instance.setImportBizNo(merchant.getId() + "_" + System.currentTimeMillis() + "_" + i);
            instance.setTransAmount("1");
            instance.setRemark("转账");
            instance.setName(name);
            instance.setStatus(PayTransStatus.FAIL);
            instance.setVersion(0L);
            instance.setIdentity(alipayNo);
            instance.setIdentityType(identityType);

            //买家昵称 和 支付宝账号&真实姓名 二选一必填一项
            if ((Strings.isNullOrEmpty(alipayNo) || Strings.isNullOrEmpty(name))) {
                instance.setErrorCode("RECEIVE_ACCOUNT_ERROR");
                instance.setErrorMsg("支付宝账号或真实姓名不能为空");
                errors.add(instance);
                continue;
            }

            if (alipayNo.contains(" ")) {
                instance.setErrorCode("RECEIVE_ACCOUNT_ERROR");
                instance.setErrorMsg("支付宝账号不能包含空格");
                errors.add(instance);
                continue;
            }
            if (name.contains(" ")) {
                instance.setErrorCode("RECEIVE_ACCOUNT_ERROR");
                instance.setErrorMsg("姓名不能包含空格");
                errors.add(instance);
                continue;
            }
            if (IdentityType.ALIPAY_LOGON_ID.getValue().equals(identityType)) {
                if (!AlipayAccountCheckUtil.isEffectiveAccount(alipayNo)) {
                    instance.setErrorCode("RECEIVE_ACCOUNT_ERROR");
                    instance.setErrorMsg("支付宝账号格式不正确");
                    errors.add(instance);
                    continue;
                }
            }
            if (!IdentityType.TAOBAO_NICKNAME.getValue().equals(identityType) && !IdentityType.ALIPAY_LOGON_ID.getValue().equals(identityType)) {
                throw new BusinessException(PoseidonErrorCode.PARAMETER_ILLEGAL, "不支持的账号类型");
            }

            payTrans.add(instance);
        }

        return new TupleModel<>(payTrans, errors);
    }

}
